/*-------------------------------------------------------------------------
 *
 * archive.c
 *	  通用WAL归档例程
 *
 * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group
 * Portions Copyright (c) 1994, Regents of the University of California
 *
 *
 * IDENTIFICATION
 *	  src/common/archive.c
 *
 *-------------------------------------------------------------------------
 */

#ifndef FRONTEND
#include "postgres.h"
#else
#include "postgres_fe.h"
#endif

#include "common/archive.h"
#include "lib/stringinfo.h"

/*
 * BuildRestoreCommand
 *
 * 构建一个恢复命令，从WAL归档中检索文件，用调用者提供的值替换
 * 支持的别名，这些值由GUC参数restore_command定义：xlogpath对应%p，xlogfname对应%f，lastRestartPointFname对应%r。
 *
 * 结果是一个为构建的恢复命令分配的palloc字符串。调用者负责释放它。如果任何所需参数为NULL，并且在调用者给出的命令中找到了对应的别名，则返回NULL。
 */
char * BuildRestoreCommand(const char *fc_restoreCommand,
					const char *fc_xlogpath,
					const char *fc_xlogfname,
					const char *fc_lastRestartPointFname)
{
	StringInfoData fc_result;
	const char *fc_sp;

	/*
	 * 构建要执行的命令。
	 */
	initStringInfo(&fc_result);

	for (fc_sp = fc_restoreCommand; *fc_sp; fc_sp++)
	{
		if (*fc_sp == '%')
		{
			switch (fc_sp[1])
			{
				case 'p':
					{
						char	   *fc_nativePath;

						/* %p：目标文件的相对路径 */
						if (fc_xlogpath == NULL)
						{
							pfree(fc_result.data);
							return NULL;
						}
						fc_sp++;

						/*
						 * 这需要使用占位符，以避免通过
						 * make_native_path()进行转换时修改输入。
						 */
						fc_nativePath = pstrdup(fc_xlogpath);
						make_native_path(fc_nativePath);
						appendStringInfoString(&fc_result,
											   fc_nativePath);
						pfree(fc_nativePath);
						break;
					}
				case 'f':
					/* %f：所需文件的文件名 */
					if (fc_xlogfname == NULL)
					{
						pfree(fc_result.data);
						return NULL;
					}
					fc_sp++;
					appendStringInfoString(&fc_result, fc_xlogfname);
					break;
				case 'r':
					/* %r：最后一个重启点的文件名 */
					if (fc_lastRestartPointFname == NULL)
					{
						pfree(fc_result.data);
						return NULL;
					}
					fc_sp++;
					appendStringInfoString(&fc_result,
										   fc_lastRestartPointFname);
					break;
				case '%':
					/* 将%%转换为一个% */
					fc_sp++;
					appendStringInfoChar(&fc_result, *fc_sp);
					break;
				default:
					/* 否则将%视为普通字符 */
					appendStringInfoChar(&fc_result, *fc_sp);
					break;
			}
		}
		else
		{
			appendStringInfoChar(&fc_result, *fc_sp);
		}
	}

	return fc_result.data;
}
